package cliente.responsehandler.xml;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.xmlpull.mxp1.MXParser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import cliente.domain.User;
import cliente.parsing.XmlParsingUtils;
import cliente.responsehandler.DocumentParseException;
import cliente.responsehandler.NonOkResponseException;

import java.io.IOException;

/**
 * Handler/Parser for response to requests to URL:
 * http://twitter.com/users/show.xml?screen_name=TWITTER_USERNAME
 */
public class XmlUserDetailsResponseHandler implements ResponseHandler<User> {

    public User handleResponse(HttpResponse httpResponse) throws IOException {

        // check if the response code is 200 (OK)
        // if not, throw exception - you can create other custom exceptions
        if (httpResponse.getStatusLine().getStatusCode() != 200) {
            /*
             * TODO 5:
             * Throw a NonOkResponseException() passing the StatusLine in HttpResponse as constructor argument
             * It makes no sense to continue executing if the request was non successful.
             */
            if(httpResponse.getStatusLine().getStatusCode() != 200){
                System.out.println("Non-OK response: "+httpResponse.getStatusLine().getReasonPhrase());
                throw new NonOkResponseException(httpResponse.getStatusLine());
            }
        }

        // create the XML pull parser
        XmlPullParser xpp = new MXParser();
        User user = null;

        try {
            xpp.setInput(httpResponse.getEntity().getContent(), null);
            xpp.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);

            // XML document read loop
            // 1. advance to next event
            int eventType = xpp.getEventType();
            // 2. get event name
            String eventName = xpp.getName();
            do {
                // 3. check event type - is this a new XML tag start?
                // remember we're still at the root of the document so we want to check for something like
                // <?xml version="1.0" encoding="UTF-8"?>
                // <user> <- what we want
                //   ...
                // </user>
                /*
                 * TODO 6:
                 * Match eventType to START_TAG events.
                 * Event constants are defined in the class XmlPullParser.
                 */
                if (eventType == XmlPullParser.START_TAG) {
                    // only START_TAG events are of interest

                    // check if the start tag is the "<user>" root element
                    if ("user".equals(eventName)) {
                        // found the "<user>" root element, parse its contents and create a User object.
                        // 4. parse the content of the root element "<user>" and fill the object
                        /**
                         * TODO 7:
                         * <user> element was found, parse its contents.
                         * set user value to parseUser() of class XmlParsingUtils
                         */
                        user = XmlParsingUtils.parseUser(xpp);
                        // since we're only looking for *1* user it is safe to bail out of the loop as soon as we
                        // manage to parse one!
                        break;
                    }

                    // ignore other root elements other than "<user>"
                    // if you wanted to find other ROOT element, say "<other>", you would add
                    // else if ("other".equals(eventName)) { ... } at the above if

                    // remember, this loop being executed at ROOT level
                    // everytime you find an element of interest, you should delegate the parsing of its content
                    // to another method, like parseXmlAndFillUser() does!

                    // in other words, every time you want to "enter" an XML element, you should do it with a
                    // separate method.
                }

                // 5. advance to next event (and get its name) until we reach the end of the document
                /**
                 * TODO 8:
                 * Advance XPP cursor by calling next() on xpp (make sure to update the value of eventType).
                 * Remember to also update eventName with getName()
                 */
                eventType = xpp.next();
                eventName = xpp.getName();
            } while (eventType != XmlPullParser.END_DOCUMENT);
        } catch (XmlPullParserException e) {
            // wrap exception and propagate it upwards
            throw new DocumentParseException(e);
        }

        if (user == null) {
            System.err.println("Warning! Failed to parse XML to create a valid User!");
            // Remember to check in your code if the result of this response handler is not null.
            // When you reach the daily API call limit, Twitter will reply with empty bodies.
            // Another alternative would be to throw an Exception, e.g.: DailyLimitExceededException
        }
        return user;
    }
}
